package ycl.security.utils;

import com.alibaba.fastjson2.JSONObject;
import io.jsonwebtoken.*;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import ycl.common.constants.SecurityConstant;
import ycl.common.result.REnum;
import ycl.common.enums.JWTEnum;
import ycl.common.exception.CustomException;

import java.util.*;

/**
 * json web token util
 *
 * @author YCL
 * @date 2022/9/22 0022 8:57
 */
public class JWTUtil {

	private static final String TOKEN_PREFIX = "Banner ";
	private static final long EXPIRE_TIME = 1000 * 60 * 60;//expire time 1 hour
	private static final String ROLE_CLAIMS = "rol";

	/**
	 * 创建 token
	 *
	 * @param username 用户名
	 * @param roles    角色
	 * @return token
	 */
	public static String createToken(String username, Collection<GrantedAuthority> roles) {
		Map<String, Object> map = new HashMap<>();
		map.put(ROLE_CLAIMS, roles);
		String token = Jwts.builder()
				.setSubject(username)
				.setClaims(map)
				.claim(JWTEnum.USERNAME.key, username)
				.setIssuedAt(new Date())
				.setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
				.signWith(SignatureAlgorithm.HS256, SecurityConstant.SIGN_KEY)
				.compact();
		return TOKEN_PREFIX + token;
	}

	/**
	 * 解析token, 解析有异常返回null
	 *
	 * @param token token
	 * @return 主体
	 */
	private static Claims analysisToken(String token) {
		try {
			String s = token.substring(TOKEN_PREFIX.length());
			return Jwts.parser()
					.setSigningKey(SecurityConstant.SIGN_KEY)
					.parseClaimsJws(s)
					.getBody();
		} catch (ExpiredJwtException | UnsupportedJwtException |
				MalformedJwtException | SignatureException |
				IllegalArgumentException ignored) {
			throw new CustomException(REnum.USED_UNAUTHORIZED);
		}
	}


	public static <T> T getMessage(String token, JWTEnum e, Class<T> c) {
		Claims claims = analysisToken(token);
		String msg = claims.get(e.key).toString();
		return JSONObject.parseObject(msg, c);
	}

	public static UsernamePasswordAuthenticationToken getUserAuthentication(String token) {
		Claims claims = analysisToken(token);
		String username = claims.get(JWTEnum.USERNAME.key).toString();
		String role = claims.get(JWTEnum.ROLE.key).toString();
		Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority(role));
		return new UsernamePasswordAuthenticationToken(username, null, authorities);
	}


	public static boolean notExpire(String token) {
		try {
			String s = token.substring(TOKEN_PREFIX.length());
			Jwts.parser()
					.setSigningKey(SecurityConstant.SIGN_KEY)
					.parseClaimsJws(s)
					.getBody();
			return true;
		} catch (ExpiredJwtException | UnsupportedJwtException |
				MalformedJwtException | SignatureException |
				IllegalArgumentException ignored) {
			return false;
		}
	}


	public static void main(String[] args) {
		String[] strings = {
				"ROLE_ADMIN",
				"ROLE_COMMON"
		};
		List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(strings);

		String token = createToken("ycl", authorityList);

		System.out.println(token);
		Claims claims = analysisToken(token);
		System.out.println(claims);
		System.out.println(notExpire(token));


	}

}
